use crate::utils::math::{max, min};
use clap::{Arg, ArgAction, Command};

const CMD_QUESTION: &str = "question";
const CMD_LONG: &str = "long";
const CMD_HISTORY: &str = "history";
const CMD_TO_KB: &str = "tokb";
const CMD_USE_KB: &str = "usekb";
const CMD_LIST_DB: &str = "listkb";
const CMD_QUES_TEMPERATURE: &str = "temperature";
const MIN_TEMPERATURE_NUM: f32 = 0.0;
const MAX_TEMPERATURE_NUM: f32 = 2.0;
const DEFAULT_HISTORY_COUNT: usize = 0;
const DEFAULT_TEMPERATURE: &str = "0.0";

pub struct Args {
    pub list_kb: bool,
    pub use_long_question: bool,
    pub short_question: Option<String>,
    pub history_count: usize,
    pub to_kb: Option<String>,
    pub kb_number: Option<usize>,
    pub temperature: f32,
}

pub fn build_args() -> Args {
    let matches = Command::new("cli_assistant")
        .version("0.1.0")
        .author("caozongying<zongying_cao@163.com>")
        .about("caozongying_cao<zongying_cao@163.com> is the author of cli assistant")
        .arg(
            Arg::new(CMD_QUESTION)
                .short('q')
                .long(CMD_QUESTION)
                .value_name("QUESTION")
                .help("问题")
                .action(ArgAction::Set),
        )
        .arg(
            Arg::new(CMD_LONG)
                .short('l')
                .long(CMD_LONG)
                .help("长问题")
                .default_value("true")
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new(CMD_HISTORY)
                .short('t')
                .long(CMD_HISTORY)
                .help("带入历史记录的数量，如果t=0，表示不带入历史记录，如果t=2则表示带入前两次会话记录, 默认值为1")
                .action(ArgAction::Set),
        )
        .arg(
            Arg::new(CMD_TO_KB)
                .short('k')
                .long(CMD_TO_KB)
                .help("将当前的回复永久存储到对应的话题中，如果这个话题存在，系统会给出提示并退出运行")
                .action(ArgAction::Set),
        )
        .arg(
            Arg::new(CMD_USE_KB)
                .short('u')
                .long(CMD_USE_KB)
                .help("使用指定编号的kb知识来回答问题")
                .action(ArgAction::Set),
        )
        .arg(
            Arg::new(CMD_LIST_DB)
                .short('s')
                .long(CMD_LIST_DB)
                .help("列出所有的kb话题")
                .default_value("false")
                .action(ArgAction::SetTrue),
        )
        .arg(
            Arg::new(CMD_QUES_TEMPERATURE)
                .short('e')
                .long(CMD_QUES_TEMPERATURE)
                .help("设置回答温度，值为0到2")
                .default_value("0")
                .action(ArgAction::Set),
        )
        .get_matches();

    let list_kb = matches.get_flag(CMD_LIST_DB);
    let use_long_question = matches.get_flag(CMD_LONG);
    let short_question = matches.get_one::<String>(CMD_QUESTION).cloned();
    let history_count = match matches
        .get_one::<String>(CMD_HISTORY)
        .unwrap_or(&DEFAULT_HISTORY_COUNT.to_string())
        .parse::<usize>()
    {
        Ok(val) => val,
        Err(err) => panic!("{:?}", err),
    };
    let to_kb = matches.get_one::<String>(CMD_TO_KB).cloned();
    let kb_number = matches
        .get_one::<String>(CMD_USE_KB)
        .map(|number| number.parse::<usize>().ok())
        .flatten();
    let temperature = max(
        min(
            MAX_TEMPERATURE_NUM,
            matches
                .get_one::<String>(CMD_QUES_TEMPERATURE)
                .unwrap_or(&DEFAULT_TEMPERATURE.to_string())
                .parse::<f32>()
                .unwrap_or(MIN_TEMPERATURE_NUM),
        ),
        MIN_TEMPERATURE_NUM,
    );

    Args {
        list_kb,
        use_long_question,
        short_question,
        history_count,
        to_kb,
        kb_number,
        temperature,
    }
}
